package com.zs.usc.configuration.common;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.zs.usc.common.BusinessException;
import com.zs.usc.common.RestRst;
import com.zs.usc.common.RestCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Zero
 * @description 全局异常处理
 * @date 2022/1/10 11:19
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    final static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Value("${spring.application.name:NA}")
    private String appName;

    @Value("${spring.profiles.active:NA}")
    private String env;

    @PostConstruct
    public void test() {
        System.out.println("log = " + log);
    }

    /**
     * 业务异常处理
     *
     * @param exception
     * @return
     * @author Zero
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public RestRst businessExceptionHandler(BusinessException exception) {
        // 记录到日志文件
        log.error(exception.getMessage(), exception);
        return RestRst.build(exception.getErrorCode().intValue(), exception.getMessage(), null);
    }

    /**
     * nullpointer exception处理
     *
     * @param exception
     * @return
     */
    @ExceptionHandler(NullPointerException.class)
    public RestRst nullPointExceptionHandler(NullPointerException exception) {
        String errMsg = "未将对象引用设置到对象实例，请检查代码！";

        // 记录到日志文件
        log.error(errMsg, exception);

        return RestRst.error(RestCode.ERROR_BUSINESS_COMMON.getCode(), errMsg);
    }

    /**
     * Mybatis plus Exception异常处理
     *
     * @param exception
     * @return
     */
    @ExceptionHandler(MybatisPlusException.class)
    public RestRst mybatisplusExceptionHandler(MybatisPlusException exception) {
        // 记录到日志文件
        log.error("Mybatis plus数据操作出现异常", exception);

        return RestRst.error(RestCode.ERROR_BUSINESS_COMMON.getCode(), exception.getMessage());
    }

    /**
     * 校验异常处理
     *
     * @return
     * @valid验证异常处理
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public RestRst ConstraintViolationExceptionHandler(ConstraintViolationException exception) {

        // 记录到日志文件
        log.error(exception.getMessage(), exception);

        List<String> msgList = exception.getConstraintViolations()
                .stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.toList());

        return RestRst.error(RestCode.ERROR_BUSINESS_COMMON.getCode(), msgList.toString());
    }


    /**
     * IllegalArgumentException异常处理返回json 状态码:400
     *
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler({IllegalArgumentException.class})
    public RestRst badRequestException(IllegalArgumentException e) {

        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;
    }

    @ResponseBody
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public RestRst handleError(MissingServletRequestParameterException e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;
    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public RestRst handleError(MethodArgumentTypeMismatchException e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;

    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RestRst handleError(MethodArgumentNotValidException e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;

    }

    @ResponseBody
    @ExceptionHandler(BindException.class)
    public RestRst handleError(BindException e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;

    }

//    @ResponseBody
//    @ExceptionHandler(ConstraintViolationException.class)
//    public ResponseResult handleError(ConstraintViolationException e) {
//        // LogUtils.send(env, instance, appName, e);
//        ResponseResult ret = ResponseResult.build(HttpStatus.BAD_REQUEST.value(), e.getMessage(), null);
//        log.error(e.toString(), e);
//        return ret;
//    }

    @ResponseBody
    @ExceptionHandler(NoHandlerFoundException.class)
    public RestRst handleError(NoHandlerFoundException e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.NOT_FOUND.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;

    }

    @ResponseBody
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public RestRst handleError(HttpMessageNotReadableException e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;

    }

    @ResponseBody
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public RestRst handleError(HttpRequestMethodNotSupportedException e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.METHOD_NOT_ALLOWED.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;

    }

    @ResponseBody
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public RestRst handleError(HttpMediaTypeNotSupportedException e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), e.getMessage(), null);
        log.error(e.toString(), e);
        return ret;

    }
    /**
     * 处理默认的系统异常，即没有封装自定义异常的情况下就到该方法处理
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public RestRst defaultErrorHandler(HttpServletRequest req, Exception e) {
        // LogUtils.send(env, instance, appName, e);
        RestRst ret = RestRst.build(RestCode.SERVER_ERROR);
        log.error(e.toString(), e);
        return ret;
    }
}
